package com.netx.ebs;
import java.util.Map;
import java.util.HashMap;

import com.netx.generics.basic.Checker;
import com.netx.generics.time.Moment;


public class Session {

	private final String _clientID;
	private final String _address;
	private User _user;
	private boolean _valid;
	private Moment _lastAccessed;
	private Moment _lastModified;
	private final Map<String,Object> _cache;

	// For SessionManager:
	Session(String clientID, String address, User user) {
		_clientID = clientID;
		_address = address;
		_user = user;
		_valid = true;
		_lastModified = _lastAccessed = new Moment();
		_cache = new HashMap<String,Object>();
	}

	public String getRemoteAddress() {
		_checkState();
		return _address;
	}

	public User getUser() {
		_checkState();
		return _user;
	}

	public void setAttribute(String name, Object value) {
		Checker.checkEmpty(name, "name");
		_checkState();
		if(value != null) {
			_cache.put(name, value);
		}
		else {
			_cache.remove(name);
		}
		_lastModified = new Moment();
	}

	public Object getAttribute(String name) {
		Checker.checkEmpty(name, "name");
		_checkState();
		return _cache.get(name);
	}

	public Moment getLastModified() {
		_checkState();
		return _lastModified;
	}
	
	public Moment getLastAccessed() {
		_checkState();
		return _lastAccessed;
	}

	public String toString() {
		_checkState();
		return _user.getUsername()+"@"+_address;
	}

	public void finalize() throws Throwable {
		_cache.clear();
		super.finalize();
	}

	// For EbsRequest.getUserSession
	void resetLastAccessed() {
		_lastAccessed = new Moment();
	}

	// For SessionManager.terminateSession
	void invalidate() {
		_cache.clear();
		_valid = false;
	}

	// For Users:
	// When changing a user's data fields, this is more practical
	// than implementing property setters for User.
	void setUser(User u) {
		_user = u;
	}

	// for SessionManager and AuthenticatorServlet
	String getClientID() {
		_checkState();
		return _clientID;
	}

	private void _checkState() {
		if(!_valid) {
			throw new IllegalStateException();
		}
	}
}
